import socket
import subprocess
import struct
import json
import os

host = ''  # 绑定所有接口
port = 8080

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 地址重用
s.bind((host, port))
s.listen(5)

print(f'Server listening on port {port}')

counter = 0
while True:
    conn_sock, conn_addr = s.accept()
    counter += 1
    print(f'Client #{counter} connected: {conn_addr}')
    
    try:
        while True:
            cmd = conn_sock.recv(1024).decode('utf-8').strip()
            if not cmd:
                print("Empty command, skipping")
                continue
                
            print(f'Executing command: {cmd}')
            
            # 执行命令
            proc = subprocess.Popen(
                cmd,
                shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=False  # 保持二进制输出
            )
            
            stdout, stderr = proc.communicate()
            total_size = len(stdout) + len(stderr)
            
            # 构建报头
            header = {
                'command': cmd,
                'exit_code': proc.returncode,
                'stdout_size': len(stdout),
                'stderr_size': len(stderr),
                'total_size': total_size,
                'encoding': 'GBK'  # Windows默认编码
            }
            
            header_json = json.dumps(header).encode('utf-8')
            header_size = len(header_json)
            
            # 发送流程：1.报头长度 2.报头数据 3.真实数据
            conn_sock.sendall(struct.pack('>I', header_size))  # 大端4字节
            conn_sock.sendall(header_json)
            
            # 分别发送stdout和stderr
            if stdout:
                conn_sock.sendall(stdout)
            if stderr:
                conn_sock.sendall(stderr)
                
    except (ConnectionResetError, BrokenPipeError):
        print(f"Client #{counter} disconnected unexpectedly")
    except Exception as e:
        print(f"Error with client #{counter}: {str(e)}")
    finally:
        conn_sock.close()
        print(f"Connection to client #{counter} closed")

s.close()